package org.hackystat.ui.projectviewer.gwt.client;

import java.util.Date;
import java.util.List;

import org.hackystat.ui.projectviewer.gwt.client.common.DateTimeFactories;
import org.hackystat.ui.projectviewer.gwt.client.common.ImageConsciousStackPanel;
import org.hackystat.ui.projectviewer.gwt.client.common.Session;
import org.hackystat.ui.projectviewer.gwt.client.common.types.ProjectViewerProperties;
import org.hackystat.ui.projectviewer.gwt.client.dataprovider.DataProviderMediator;
import org.hackystat.ui.projectviewer.gwt.client.validator.InputValidator;
import org.hackystat.ui.projectviewer.gwt.client.widgets.InvitationListWidget;
import org.hackystat.ui.projectviewer.gwt.client.widgets.ProjectListWidget;
import org.hackystat.ui.projectviewer.gwt.client.widgets.UserActionWidget;

import com.allen_sauer.gwt.log.client.Log;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.Cookies;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.FocusListener;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.PasswordTextBox;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

/**
 * The main screen left panel which hosts next comfiguration widgets:
 * <ul>
 * <li> Hosts configuration widget: sensorbase, DPD and telemetry </li>
 * <li> User configuration widget: username and password along with registration button </li>
 * <li> User projects list: which allows project selection and provides projects action menu </li>
 * <li> User invitations widget: allows user to accept or decline invitations. </li>
 * </ul>
 *
 * @author Pavel Senin.
 *
 */
public class ConfigurationWidgetPanel extends Composite implements FocusListener, ClickListener {

  /* The new line character constant. */
  private static final String newLineChar = "<br />";

  /* The stack panel which contains all configuration widgets. */
  final ImageConsciousStackPanel outer = new ImageConsciousStackPanel();

  // Sensorbase host settings panel and elements
  //
  // most outer panel for settings
  final VerticalPanel hostSettingsPanel = new VerticalPanel();
  // top outer panel for the image and for both statuses
  final HorizontalPanel hostColumns = new HorizontalPanel();
  final VerticalPanel feedbackRows = new VerticalPanel();
  // host label and image
  final Label hostLabel = new Label("Host");
  final Image hostPanelImage = new Image(Images.HOST_IMAGE);
  // three feedback labels
  private final HTML sensorbaseStatus = new HTML("Sensorbase status.");
  private final HTML dpdStatus = new HTML("DPD status.");
  private final HTML telemetryStatus = new HTML("Telemetry status.");
  // bottom vertical panel for both URI examples
  final HorizontalPanel uriColumns = new HorizontalPanel();
  final VerticalPanel uriRows = new VerticalPanel();
  final Label uriSectionTitleLabel = new Label("URI:");
  final Label sensorbaseHostLabel = new Label();
  final Label dpdHostLabel = new Label();
  final Label telemetryHostLabel = new Label();

  // User authentication data settings panel and elements
  //
  final VerticalPanel userSettingsPanel = new VerticalPanel();
  final Image userPanelImage = new Image(Images.USER_IMAGE);
  final Label userPanelTitle = new Label("User");
  final HTML userPanelFeedback = new HTML("User status.");
  final VerticalPanel userRows = new VerticalPanel();
  final HorizontalPanel userColumns = new HorizontalPanel();
  final FlexTable userTableLayout = new FlexTable();
  final Label userEmailLabel = new Label("E-mail:");
  final TextBox userEmailBox = new TextBox();
  final Label userPassLabel = new Label("Password:");
  final PasswordTextBox userPassBox = new PasswordTextBox();
  final UserActionWidget userActionsPanel = new UserActionWidget();

  // Project list panel elements
  //
  final VerticalPanel projectListPanel = new VerticalPanel();
  final Image projectPanelImage = new Image(Images.OPEN_BOOK);
  final Label projectPanelTitle = new Label("Projects");
  final HTML projectsPanelSubTitle = new HTML("Projects and Invitations");
  final ProjectListWidget projectListWidget = new ProjectListWidget();
  final InvitationListWidget invitationListWidget = new InvitationListWidget();
  final HorizontalPanel projectColumns = new HorizontalPanel();
  final VerticalPanel projectRows = new VerticalPanel();

  private Boolean firstCalInit;
  private Boolean sensorbaseHostStatus;
  private Boolean dpdHostStatus;
  private Boolean telemetryHostStatus;
  private Boolean userStatus;

  // one year for cookies
  final Date cookieExpires = new Date((new Date()).getTime() + (1000 * 60 * 60 * 24 * 365));

  // needed for profiling
  private long startTimeMillis;

  /**
   * Constructor.
   *
   * @param parent The panel parent handler.
   */
  public ConfigurationWidgetPanel(ProjectViewer parent) {

    // set the style of the most outer panel
    outer.setStyleName(CSSStyles.CONFIGURATION_PANEL);

    // make sure that this is the first call and we have no idea about authentication yet
    this.firstCalInit = true;
    this.sensorbaseHostStatus = false;
    this.dpdHostStatus = false;
    this.telemetryHostStatus = false;
    this.userStatus = false;

    // First Stack Item: Host Settings
    //
    uriColumns.setStyleName(CSSStyles.CP_CONTENT_OUTER);
    uriColumns.add(uriSectionTitleLabel);
    uriSectionTitleLabel.setStyleName(CSSStyles.CP_CONTENT_GREEN_LABEL_LEFT);
    sensorbaseHostLabel.setText("Example: http://hackystat.org:9876/sensorbase");
    sensorbaseHostLabel.setStyleName(CSSStyles.HOST_EXAMPLE);
    uriRows.add(sensorbaseHostLabel);
    dpdHostLabel.setText("Example: http://hackystat.org:9877/dailyprojectdata");
    dpdHostLabel.setStyleName(CSSStyles.HOST_EXAMPLE);
    uriRows.add(dpdHostLabel);
    telemetryHostLabel.setText("Example: http://hackystat.org:9878/telemetry");
    telemetryHostLabel.setStyleName(CSSStyles.HOST_EXAMPLE);
    uriRows.add(telemetryHostLabel);
    uriColumns.add(uriRows);
    hostSettingsPanel.setStyleName(CSSStyles.USER_SETTINGS);
    hostSettingsPanel.add(uriColumns);
    outer.add(hostSettingsPanel, "<div id=\"hostPanelTitleSlot\"></div>", true);

    // and panel header for the host settings, we MUST init and attach it later
    //
    hostPanelImage.setStyleName(CSSStyles.CP_IMAGE);
    hostColumns.add(hostPanelImage);
    hostLabel.setStyleName(CSSStyles.SETTINGS_TITLE);
    feedbackRows.add(hostLabel);
    sensorbaseStatus.setStyleName(CSSStyles.HOST_EXAMPLE);
    feedbackRows.add(sensorbaseStatus);
    dpdStatus.setStyleName(CSSStyles.HOST_EXAMPLE);
    feedbackRows.add(dpdStatus);
    telemetryStatus.setStyleName(CSSStyles.HOST_EXAMPLE);
    feedbackRows.add(telemetryStatus);
    hostColumns.add(feedbackRows);

    // Second Stack Item: User Settings
    //
    userSettingsPanel.setStyleName(CSSStyles.USER_SETTINGS);
    userSettingsPanel.add(userTableLayout);
    userTableLayout.setCellPadding(0);
    userTableLayout.setCellSpacing(0);
    userTableLayout.setWidget(0, 0, userEmailLabel);
    userEmailLabel.setStyleName(CSSStyles.CP_CONTENT_GREEN_LABEL_LEFT);
    userTableLayout.setWidget(0, 1, userEmailBox);
    userTableLayout.setWidget(1, 0, userPassLabel);
    userPassLabel.setStyleName(CSSStyles.CP_CONTENT_GREEN_LABEL_LEFT);
    userTableLayout.setWidget(1, 1, userPassBox);
    userSettingsPanel.add(userActionsPanel);
    userActionsPanel.addClickListener(this);
    String userCookie = Cookies.getCookie("user");
    if (userCookie != null) {
      this.userEmailBox.setText(userCookie);
    }
    String passwordCookie = Cookies.getCookie("password");
    if (passwordCookie != null) {
      userPassBox.setText(passwordCookie);
    }
    userPassBox.addFocusListener(this);
    outer.add(userSettingsPanel, "<div id=\"userPanelTitleSlot\"></div>", true);

    // and panel header for the stack, we MUST init and attach it later
    userPanelImage.setStyleName(CSSStyles.CP_IMAGE);
    userColumns.add(userPanelImage);
    userRows.add(userPanelTitle);
    userPanelTitle.setStyleName(CSSStyles.SETTINGS_TITLE);
    userRows.add(userPanelFeedback);
    userPanelFeedback.setStyleName(CSSStyles.HOST_EXAMPLE);
    userColumns.add(userRows);

    // now comes project list
    //
    /* Third Stack Item: Project List Widget and buttons */
    projectListPanel.setStyleName(CSSStyles.USER_SETTINGS);
    projectListPanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);
    projectListPanel.add(projectListWidget);
    projectListPanel.add(invitationListWidget);
    invitationListWidget.setVisible(false);
    outer.add(projectListPanel, "<div id=\"projectListPanelTitleSlot\"></div>", true);

    // and panel header for the stack, we MUST init and attach it later
    projectPanelImage.setStyleName(CSSStyles.CP_IMAGE);
    projectColumns.add(projectPanelImage);
    projectRows.add(projectPanelTitle);
    projectPanelTitle.setStyleName(CSSStyles.SETTINGS_TITLE);
    projectRows.add(projectsPanelSubTitle);
    projectsPanelSubTitle.setStyleName(CSSStyles.HOST_EXAMPLE);
    projectColumns.add(projectRows);

    // get RPC and get sensorbase, dpd and client information
    //
    getProperties();
    this.initWidget(outer);

  }

  /**
   * {@inheritDoc}
   */
  public void onAttach() {
    super.onAttach();
    RootPanel.get("hostPanelTitleSlot").add(hostColumns);
    hostColumns.setTitle("The sensorbase host configured through the properties file.");
    RootPanel.get("userPanelTitleSlot").add(userColumns);
    userColumns.setTitle("User authentications configuration.");
    RootPanel.get("projectListPanelTitleSlot").add(projectColumns);
    projectColumns.setTitle("The project and invitations list widgget.");
  }

  /**
   * Does RPC call and gets configured properties.
   */
  private final void getProperties() {
    // lock RPC
    if (DataProviderMediator.getInstance().lock()) {
      if (Log.isDebugEnabled()) {
        Log.debug("PV-CP: mediator locked, asking for properties.");
        startTimeMillis = System.currentTimeMillis();
      }
      hostPanelImage.setUrl(Images.WAIT_IMAGE);
      this.sensorbaseStatus.setText("Searching for the properties file.");
      // read properties at the server side
      DataProviderMediator.getInstance().getProjectViewerProperties(
          new AsyncCallback<ProjectViewerProperties>() {
            public void onSuccess(ProjectViewerProperties result) {
              DataProviderMediator.getInstance().unlock();
              if (Log.isDebugEnabled()) {
                Log.debug("PV-CP: mediator unlocked, success in "
                    + (System.currentTimeMillis() - startTimeMillis) / 1000F);
              }
              // check for empty result, if so - get error code
              if (null == result) {
                hostPanelImage.setUrl(Images.HOST_INVALID);
                sensorbaseStatus.setText("Unable to get properties.");
                sensorbaseStatus.setStyleName(CSSStyles.SETTINGS_INVALID_LABEL_STYLE);
                if (Log.isDebugEnabled()) {
                  Log.debug("PV-CP: null result fetched, getting error message.");
                }
                // --><><>< lock RPC and get error code, just let it go if unable to lock
                if (DataProviderMediator.getInstance().lock()) {
                  DataProviderMediator.getInstance().getException(new AsyncCallback<String>() {
                    public void onSuccess(String result) {
                      DataProviderMediator.getInstance().unlock();
                      Window.alert("Unable to read properties file, make sure you have one, "
                          + "please provide feedback to hackystat-dev@googlegroups.com. \n"
                          + " Error: " + result);
                    }

                    public void onFailure(Throwable ex) {
                      DataProviderMediator.getInstance().unlock();
                      Window.alert("Unknown exception happend during RPC call. \n Please provide "
                          + "feedback to hackystat-dev@googlegroups.com. \n Error: "
                          + ex.getMessage());
                    }
                  });
                }
                // --><><>< end of error retrieving code.
              }
              else {
                // looks like everything is OK - confirming hosts
                setHosts(result);
              }
            }

            public void onFailure(Throwable ex) {
              DataProviderMediator.getInstance().unlock();
              Window.alert("Unknown exception happend during RPC call. \n Please provide feedback "
                  + "to hackystat-dev@googlegroups.com. \n Error: " + ex.getMessage());
            }
          });
    }
    else {
      Window.alert("RPC is locked, unable to proceed with communications. \n Please provide "
          + "feedback to hackystat-dev@googlegroups.com.");
    }
  }

  /**
   * This method sets the name of the host uri.
   *
   * @param properties the sensorbase and DPD hosts domain and path
   */
  private final void setHosts(ProjectViewerProperties properties) {
    this.sensorbaseHostLabel.setText(properties.getSensorbaseHost());
    this.dpdHostLabel.setText(properties.getDPDHost());
    this.telemetryHostLabel.setText(properties.getTelemetryHost());
    this.sensorbaseStatus.setText("Properties file located.");
    this.hostPanelImage.setUrl(Images.HOST_IMAGE);
    if (this.firstCalInit) {
      rpcConfirmSensorbaseHost();
      this.firstCalInit = false;
    }
  }

  /**
   * Check with the servlet to see if the host is valid.
   */
  public void rpcConfirmSensorbaseHost() {
    if (DataProviderMediator.getInstance().lock()) {
      if (Log.isDebugEnabled()) {
        Log.debug("PV-CP: mediator locked, confirming sensorbase host.");
        startTimeMillis = System.currentTimeMillis();
      }
      this.sensorbaseStatus.setHTML("Validating the Sensorbase host is at" + newLineChar + "URI: "
          + sensorbaseHostLabel.getText());
      hostPanelImage.setUrl(Images.WAIT_IMAGE);
      DataProviderMediator.getInstance().confirmSensorbaseHost(this.sensorbaseHostLabel.getText(),
          new AsyncCallback<Boolean>() {
            public void onSuccess(Boolean result) {
              DataProviderMediator.getInstance().unlock();
              if (Log.isDebugEnabled()) {
                Log.debug("PV-CP: mediator unlocked, confirming sensorbase in "
                    + (System.currentTimeMillis() - startTimeMillis) / 1000F);
              }
              if (result) {
                // even if everything OK we keeping wait image running
                Session.getInstance().setSensorbaseHost(sensorbaseHostLabel.getText());
                sensorbaseHostStatus = true;
                rpcConfirmDPDHost();
              }
              else {
                // looks like we are not OK with sensorbase in here
                hostPanelImage.setUrl(Images.HOST_INVALID);
                sensorbaseStatus.setText("Unable to confirm sensorbase host...");
                sensorbaseStatus.setStyleName(CSSStyles.SETTINGS_INVALID_LABEL_STYLE);
                // --><><>< lock RPC and display some clues about why unable to confirm host
                if (DataProviderMediator.getInstance().lock()) {
                  DataProviderMediator.getInstance().getException(new AsyncCallback<String>() {
                    public void onSuccess(String result) {
                      DataProviderMediator.getInstance().unlock();
                      Window.alert("Unable to confirm sensorbase host at "
                          + sensorbaseHostLabel.getText() + ", please provide feedback "
                          + "to hackystat-dev@googlegroups.com. \n Error: " + result);
                    }

                    public void onFailure(Throwable ex) {
                      DataProviderMediator.getInstance().unlock();
                      Window.alert("Unknown exception happend during RPC call. \n Please provide "
                          + "feedback to hackystat-dev@googlegroups.com. \n Error: "
                          + ex.getMessage());
                    }
                  });
                }
                // --><><>< end of error retrieving code.
              }
              // updatePanelImages();
            }

            public void onFailure(Throwable ex) {
              DataProviderMediator.getInstance().unlock();
              Window.alert("Unknown exception happend during RPC call. \n Please provide feedback "
                  + "to hackystat-dev@googlegroups.com. \n Error: " + ex.getMessage());
            }
          });
    }
    else {
      Window.alert("RPC is locked, unable to proceed with communications. \n Please provide "
          + "feedback to hackystat-dev@googlegroups.com.");
    }

  }

  /**
   * Check with the servlet to see if the host is valid.
   */
  public void rpcConfirmDPDHost() {
    if (DataProviderMediator.getInstance().lock()) {
      this.dpdStatus.setHTML("Validating the DPD host is at" + newLineChar + "URI: "
          + dpdHostLabel.getText());
      if (Log.isDebugEnabled()) {
        Log.debug("PV-CP: mediator locked, confirming DPD host.");
        startTimeMillis = System.currentTimeMillis();
      }
      DataProviderMediator.getInstance().confirmDPDHost(this.dpdHostLabel.getText(),
          new AsyncCallback<Boolean>() {
            public void onSuccess(Boolean result) {
              DataProviderMediator.getInstance().unlock();
              if (Log.isDebugEnabled()) {
                Log.debug("PV-CP: mediator unlocked, confirming dpd in "
                    + (System.currentTimeMillis() - startTimeMillis) / 1000F);
              }
              if (result) {
                Session.getInstance().setDPDHost(dpdHostLabel.getText());
                dpdHostStatus = true;
                rpcConfirmTelemetryHost();
              }
              else {
                // looks like we are not OK with sensorbase in here
                hostPanelImage.setUrl(Images.HOST_INVALID);
                dpdStatus.setText("Unable to confirm DPD host...");
                dpdStatus.setStyleName(CSSStyles.SETTINGS_INVALID_LABEL_STYLE);
                // --><><>< lock RPC and display some clues about why unable to confirm host
                if (DataProviderMediator.getInstance().lock()) {
                  DataProviderMediator.getInstance().getException(new AsyncCallback<String>() {
                    public void onSuccess(String result) {
                      DataProviderMediator.getInstance().unlock();
                      Window.alert("Unable to confirm DPD host at " + dpdHostLabel.getText()
                          + ", please provide feedback "
                          + "to hackystat-dev@googlegroups.com. \n Error: " + result);
                    }

                    public void onFailure(Throwable ex) {
                      DataProviderMediator.getInstance().unlock();
                      Window.alert("Unknown exception happend during RPC call. \n Please provide "
                          + "feedback to hackystat-dev@googlegroups.com. \n Error: "
                          + ex.getMessage());
                    }
                  });
                }
                // --><><>< end of error retrieving code.
              }
              updatePanelImages();
            }

            public void onFailure(Throwable ex) {
              DataProviderMediator.getInstance().unlock();
              Window.alert("Unknown exception happend during RPC call. \n Please provide feedback "
                  + "to hackystat-dev@googlegroups.com. \n Error: " + ex.getMessage());
            }
          });
    }
    else {
      Window.alert("RPC is locked, unable to proceed with communications. \n Please provide "
          + "feedback to hackystat-dev@googlegroups.com.");
    }
  }

  /**
   * Check with the servlet to see if the host is valid.
   */
  public void rpcConfirmTelemetryHost() {
    if (DataProviderMediator.getInstance().lock()) {
      this.telemetryStatus.setHTML("Validating the Telemetry host is at" + newLineChar + "URI: "
          + telemetryHostLabel.getText());
      if (Log.isDebugEnabled()) {
        Log.debug("PV-CP: mediator locked, confirming sensorbase host.");
        startTimeMillis = System.currentTimeMillis();
      }
      DataProviderMediator.getInstance().confirmTelemetryHost(this.telemetryHostLabel.getText(),
          new AsyncCallback<Boolean>() {
            public void onSuccess(Boolean result) {
              DataProviderMediator.getInstance().unlock();
              if (Log.isDebugEnabled()) {
                Log.debug("PV-CP: mediator unlocked, confirming telemetry in "
                    + (System.currentTimeMillis() - startTimeMillis) / 1000F);
              }
              if (result) {
                Session.getInstance().setTelemetryHost(telemetryHostLabel.getText());
                telemetryHostStatus = true;
                rpcConfirmUser();
              }
              else {
                // looks like we are not OK with sensorbase in here
                hostPanelImage.setUrl(Images.HOST_INVALID);
                telemetryStatus.setText("Unable to confirm Telemetry host...");
                telemetryStatus.setStyleName(CSSStyles.SETTINGS_INVALID_LABEL_STYLE);
                // --><><>< lock RPC and display some clues about why unable to confirm host
                if (DataProviderMediator.getInstance().lock()) {
                  DataProviderMediator.getInstance().getException(new AsyncCallback<String>() {
                    public void onSuccess(String result) {
                      DataProviderMediator.getInstance().unlock();
                      Window.alert("Unable to confirm telemetry host at "
                          + telemetryHostLabel.getText() + ", please provide feedback "
                          + "to hackystat-dev@googlegroups.com. \n Error: " + result);
                    }

                    public void onFailure(Throwable ex) {
                      DataProviderMediator.getInstance().unlock();
                      Window.alert("Unknown exception happend during RPC call. \n Please provide "
                          + "feedback to hackystat-dev@googlegroups.com. \n Error: "
                          + ex.getMessage());
                    }
                  });
                }
                // --><><>< end of error retrieving code.
              }
              updatePanelImages();
            }

            public void onFailure(Throwable ex) {
              DataProviderMediator.getInstance().unlock();
              Window.alert("Unknown exception happend during RPC call. \n Please provide feedback "
                  + "to hackystat-dev@googlegroups.com. \n Error: " + ex.getMessage());
            }
          });
    }
    else {
      Window.alert("RPC is locked, unable to proceed with communications. \n Please provide "
          + "feedback to hackystat-dev@googlegroups.com.");
    }

  }

  /**
   * Check with the servlet to see if the user/key is valid.
   */
  public void rpcConfirmUser() {
    if (DataProviderMediator.getInstance().lock()) {
      if (Log.isDebugEnabled()) {
        Log.debug("PV-CP: mediator locked, confirming the user.");
        startTimeMillis = System.currentTimeMillis();
      }
      this.userPanelImage.setUrl(Images.WAIT_IMAGE);
      DataProviderMediator.getInstance().confirmUser(Session.getInstance().getSensorbaseHost(),
          userEmailBox.getText(), userPassBox.getText(), new AsyncCallback<Boolean>() {
            public void onSuccess(Boolean result) {
              DataProviderMediator.getInstance().unlock();
              if (Log.isDebugEnabled()) {
                Log.debug("PV-CP: mediator unlocked, confirming user in "
                    + (System.currentTimeMillis() - startTimeMillis) / 1000F);
              }
              if (result) {
                Session.getInstance().setUser(userEmailBox.getText());
                Session.getInstance().setPassword(userPassBox.getText());
                Cookies.setCookie("user", userEmailBox.getText(), cookieExpires);
                Cookies.setCookie("password", userPassBox.getText(), cookieExpires);
                userPanelImage.setUrl(Images.USER_VALID);
                userPanelFeedback
                    .setText("User " + Session.getInstance().getUser() + " confirmed.");
                userPanelFeedback.setStyleName(CSSStyles.SETTINGS_VALID_LABEL_STYLE);
                outer.showStack(2);
                updateProjectListWidget();
              }
              else {
                outer.showStack(1);
                // looks like we are not OK with sensorbase in here
                userPanelImage.setUrl(Images.USER_INVALID);
                userPanelFeedback.setText("Unable to confirm User...");
                userPanelFeedback.setStyleName(CSSStyles.SETTINGS_INVALID_LABEL_STYLE);
                // --><><>< lock RPC and display some clues about why unable to confirm host
                if (DataProviderMediator.getInstance().lock()) {
                  DataProviderMediator.getInstance().getException(new AsyncCallback<String>() {
                    public void onSuccess(String result) {
                      DataProviderMediator.getInstance().unlock();
                      Window.alert("Unable to confirm User at "
                          + Session.getInstance().getSensorbaseHost()
                          + ", please provide feedback "
                          + "to hackystat-dev@googlegroups.com. \n Error: " + result);
                    }

                    public void onFailure(Throwable ex) {
                      DataProviderMediator.getInstance().unlock();
                      Window.alert("Unknown exception happend during RPC call. \n Please provide "
                          + "feedback to hackystat-dev@googlegroups.com. \n Error: "
                          + ex.getMessage());
                    }
                  });
                }
                setUserStatus(result);
              }
            }

            public void onFailure(Throwable ex) {
              DataProviderMediator.getInstance().unlock();
              Window.alert("Unknown exception happend during RPC call. \n Please provide feedback "
                  + "to hackystat-dev@googlegroups.com. \n Error: " + ex.getMessage());
            }
          });
    }
    else {
      Window.alert("RPC is locked, unable to proceed with communications. \n Please provide "
          + "feedback to hackystat-dev@googlegroups.com.");
    }
  }

  /**
   * Get the project list and invitations list alive.
   */
  public void updateProjectListWidget() {
    // part1 - get project list
    if (DataProviderMediator.getInstance().lock()) {
      projectPanelImage.setUrl(Images.WAIT_IMAGE);
      DataProviderMediator.getInstance().getProjectIndex(Session.getInstance().getSensorbaseHost(),
          userEmailBox.getText(), userPassBox.getText(), new AsyncCallback<List<String>>() {
            public void onSuccess(List<String> result) {
              DataProviderMediator.getInstance().unlock();
              if (null == result) {
                // --><><>< lock RPC and display some clues about why we are getting null
                if (DataProviderMediator.getInstance().lock()) {
                  DataProviderMediator.getInstance().getException(new AsyncCallback<String>() {
                    public void onSuccess(String result) {
                      DataProviderMediator.getInstance().unlock();
                      Window.alert("Unable to get projects list, please provide feedback "
                          + "to hackystat-dev@googlegroups.com. \n Error: " + result);
                    }

                    public void onFailure(Throwable ex) {
                      DataProviderMediator.getInstance().unlock();
                      Window.alert("Unknown exception happend during RPC call. \n Please provide "
                          + "feedback to hackystat-dev@googlegroups.com. \n Error: "
                          + ex.getMessage());
                    }
                  });
                } // --><><>< end of error retrieving code.
              }
              else {
                projectListWidget.setProjectIndex(result);
                projectPanelImage.setUrl(Images.OPEN_BOOK);
                updateInvitationListWidget();
              }
            }

            public void onFailure(Throwable ex) {
              DataProviderMediator.getInstance().unlock();
              Window.alert("Unknown exception happend during RPC call. \n Please provide feedback "
                  + "to hackystat-dev@googlegroups.com. \n Error: " + ex.getMessage());
            }
          });
    }
    else {
      Window.alert("RPC is locked, unable to proceed with communications. \n Please provide "
          + "feedback to hackystat-dev@googlegroups.com.");
    }
  }

  /**
   * Updates the content of invitations list.
   */
  public void updateInvitationListWidget() {
    // part2 - get invitations
    GWT.log("Getting list of invitations", null);
    if (DataProviderMediator.getInstance().lock()) {
      projectPanelImage.setUrl(Images.WAIT_IMAGE);
      DataProviderMediator.getInstance().getInvitationsList(sensorbaseHostLabel.getText(),
          userEmailBox.getText(), userPassBox.getText(), new AsyncCallback<List<String>>() {
            public void onSuccess(List<String> result) {
              DataProviderMediator.getInstance().unlock();
              if (null == result) {
                // --><><>< lock RPC and display some clues about why we are getting null
                if (DataProviderMediator.getInstance().lock()) {
                  DataProviderMediator.getInstance().getException(new AsyncCallback<String>() {
                    public void onSuccess(String result) {
                      DataProviderMediator.getInstance().unlock();
                      Window.alert("Unable to get invitations list, please provide feedback "
                          + "to hackystat-dev@googlegroups.com. \n Error: " + result);
                    }

                    public void onFailure(Throwable ex) {
                      DataProviderMediator.getInstance().unlock();
                      Window.alert("Unknown exception happend during RPC call. \n Please provide "
                          + "feedback to hackystat-dev@googlegroups.com. \n Error: "
                          + ex.getMessage());
                    }
                  });
                } // --><><>< end of error retrieving code.
              }
              else {
                if (!result.isEmpty()) {
                  invitationListWidget.setInvitationsIndex(result);
                  invitationListWidget.setVisible(true);
                }
                else {
                  invitationListWidget.clean();
                  invitationListWidget.setVisible(false);
                }
              }
              projectPanelImage.setUrl(Images.OPEN_BOOK);
            }

            public void onFailure(Throwable ex) {
              DataProviderMediator.getInstance().unlock();
              Window.alert("Unknown exception happend during RPC call. \n Please provide feedback "
                  + "to hackystat-dev@googlegroups.com. \n Error: " + ex.getMessage());
            }
          });
    }
    else {
      Window.alert("RPC is locked, unable to proceed with communications. \n Please provide "
          + "feedback to hackystat-dev@googlegroups.com.");
    }

  }

  /**
   * This method sets the state of the user & key validation.
   *
   * @param userValid Boolean represents the state of the user valid=true, invalid=false
   */
  public void setUserStatus(Boolean userValid) {
    if (userValid) {
      userStatus = true;
      Cookies.setCookie("user", userEmailBox.getText(), cookieExpires);
      Cookies.setCookie("password", userPassBox.getText(), cookieExpires);
    }
    else {
      userStatus = false;
    }
    updatePanelImages();
    if (userValid.booleanValue() && this.firstCalInit) {
      outer.showStack(2);
    }
  }

  /**
   * This method sets the correct panel Images from the host and user status.
   */
  public void updatePanelImages() {
    String timestamp = DateTimeFactories.getInstance().getBodyfactory().format(new Date());
    if (sensorbaseHostStatus) {
      sensorbaseStatus.setHTML(timestamp + ", Sensorbase contacted.");
      sensorbaseStatus.setStyleName(CSSStyles.SETTINGS_VALID_LABEL_STYLE);
      if (dpdHostStatus) {
        dpdStatus.setHTML(timestamp + ", DPD contacted.");
        dpdStatus.setStyleName(CSSStyles.SETTINGS_VALID_LABEL_STYLE);
        if (telemetryHostStatus) {
          hostPanelImage.setUrl(Images.HOST_VALID);
          telemetryStatus.setHTML(timestamp + ", Sensorbase contacted.");
          telemetryStatus.setStyleName(CSSStyles.SETTINGS_VALID_LABEL_STYLE);
          if (userStatus) {
            userPanelImage.setUrl(Images.USER_VALID);
            userPanelFeedback.setText("User " + userEmailBox.getText() + " authorized.");
            userPanelFeedback.setStyleName(CSSStyles.SETTINGS_VALID_LABEL_STYLE);
          }
          else {
            userPanelImage.setUrl(Images.USER_INVALID);
            userPanelFeedback.setText("User " + userEmailBox.getText() + " authorization failed.");
            this.userPanelFeedback.setStyleName(CSSStyles.SETTINGS_INVALID_LABEL_STYLE);
          }
        }
      }
    }
    else {
      hostPanelImage.setUrl(Images.HOST_INVALID);
      sensorbaseStatus.setHTML(timestamp + ", Sensorbase unavailable.");
      sensorbaseStatus.setStyleName(CSSStyles.SETTINGS_INVALID_LABEL_STYLE);
      dpdStatus.setHTML(timestamp + ", DPD unavailable.");
      dpdStatus.setStyleName(CSSStyles.SETTINGS_INVALID_LABEL_STYLE);
      userPanelImage.setUrl(Images.USER_IMAGE);
      userPanelFeedback.setText("Need a valid host, before checking user credentials.");
      userPanelFeedback.setStyleName(CSSStyles.HOST_EXAMPLE);
    }
  }

  /**
   * {@inheritDoc}
   */
  public void onFocus(Widget sender) {
    assert true;
  }

  /**
   * {@inheritDoc}
   */
  public void onLostFocus(Widget sender) {
    // if ((sender.equals(userEmailBox)) || (sender.equals(userPassBox))) {
    // rpcConfirmUser();
    // }
  }

  /**
   * {@inheritDoc}
   */
  public void onClick(Widget sender) {
    if (sender == userActionsPanel) {
      String action = userActionsPanel.getAction();
      if (Log.isDebugEnabled()) {
        Log.debug("PV-CP: got user action: " + action);
      }
      if (action.equalsIgnoreCase(UserActionWidget.ACTION_REGISTER)) {
        String userEmail = userEmailBox.getText();
        if (InputValidator.getInstance().validateEmail(userEmail)) {
          if (DataProviderMediator.getInstance().lock()) {
            if (Log.isDebugEnabled()) {
              Log.debug("PV-CP: Registering new user " + userEmail);
            }
            userPanelImage.setUrl(Images.WAIT_IMAGE);
            DataProviderMediator.getInstance().registerUser(sensorbaseHostLabel.getText(),
                userEmail, new AsyncCallback<Boolean>() {
                  public void onSuccess(Boolean result) {
                    DataProviderMediator.getInstance().unlock();
                    if (Log.isDebugEnabled()) {
                      Log.debug("PV-CP: mediator unlocked, registered user in "
                          + (System.currentTimeMillis() - startTimeMillis) / 1000F);
                    }
                    if (result) {
                      userPanelFeedback.setText("User " + userEmailBox.getText()
                          + " registered, Check your email for password.");
                      userPanelFeedback.setStyleName(CSSStyles.SETTINGS_VALID_LABEL_STYLE);
                      userPanelImage.setUrl(Images.USER_IMAGE);
                    }
                    else {
                      userPanelFeedback
                          .setText("UNABLE to register user " + userEmailBox.getText());
                      userPanelFeedback.setStyleName(CSSStyles.SETTINGS_INVALID_LABEL_STYLE);
                      userPanelImage.setUrl(Images.USER_INVALID);
                      // --><><>< lock RPC and display some clues about why unable to confirm host
                      if (DataProviderMediator.getInstance().lock()) {
                        DataProviderMediator.getInstance().getException(
                            new AsyncCallback<String>() {
                              public void onSuccess(String result) {
                                DataProviderMediator.getInstance().unlock();
                                Window.alert("Unable to Register User at "
                                    + Session.getInstance().getSensorbaseHost()
                                    + ", please provide feedback "
                                    + "to hackystat-dev@googlegroups.com. \n Error: " + result);
                              }

                              public void onFailure(Throwable ex) {
                                DataProviderMediator.getInstance().unlock();
                                Window.alert("Unknown exception happend during RPC call. \n"
                                    + " Please provide feedback to "
                                    + "hackystat-dev@googlegroups.com. \n Error: "
                                    + ex.getMessage());
                              }
                            });
                      }
                    }
                    // DataProviderMediator.getInstance().unlock();
                    // projectPanelImage.setUrl(Images.OPEN_BOOK);
                  }

                  public void onFailure(Throwable ex) {
                    DataProviderMediator.getInstance().unlock();
                    Window.alert("Unknown exception happend during RPC call. \n Please provide "
                        + "feedback to hackystat-dev@googlegroups.com. \n Error: "
                        + ex.getMessage());
                  }
                });
          }
          else {
            Window.alert("RPC is locked, unable to proceed with communications. \n Please provide "
                + "feedback to hackystat-dev@googlegroups.com.");
          }
        }
      }
      else if (action.equalsIgnoreCase(UserActionWidget.ACTION_LOGIN)) {
        rpcConfirmUser();
      }
    }
  }

  /**
   * Refreshes widget.
   */
  public void refreshLists() {
    updateProjectListWidget();
    projectListWidget.resetButtons();
    invitationListWidget.resetButtons();
  }

  /**
   * Resets (pops) all buttons.
   */
  public void resetButtons() {
    projectListWidget.resetButtons();
    invitationListWidget.resetButtons();
  }
}
